package com.tich.utils;

import java.security.SecureRandom;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 64位有序ID生成器（兼容Long类型）
 * 结构：41位时间戳 + 5位数据中心ID + 5位机器ID + 13位序列号
 * 总位数：41+5+5+13=64位
 */
public class IdGeneratorUtil {
    // 起始时间戳（2020-01-01 00:00:00）
    private final long startTimeStamp = 1577836800000L;
    // 各部分占用位数
    private final long dataCenterIdBits = 5L;  // 最多32个数据中心
    private final long machineIdBits = 5L;     // 每个数据中心最多32台机器
    private final long sequenceBits = 13L;     // 每毫秒最多生成8192个ID

    // 最大值
    private final long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits); // 31
    private final long maxMachineId = -1L ^ (-1L << machineIdBits);       // 31
    private final long maxSequence = -1L ^ (-1L << sequenceBits);          // 8191

    // 位移量
    private final long machineIdShift = sequenceBits;
    private final long dataCenterIdShift = sequenceBits + machineIdBits;
    private final long timestampShift = sequenceBits + machineIdBits + dataCenterIdBits;

    private final long dataCenterId;
    private final long machineId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;
    private final AtomicInteger retryCount = new AtomicInteger(0);

    // 单例模式
    private static final IdGeneratorUtil INSTANCE = new IdGeneratorUtil(1, 1);

    public static IdGeneratorUtil getInstance() {
        return INSTANCE;
    }

    private IdGeneratorUtil(long dataCenterId, long machineId) {
        if (dataCenterId > maxDataCenterId || dataCenterId < 0) {
            throw new IllegalArgumentException("DataCenter ID must be between 0 and " + maxDataCenterId);
        }
        if (machineId > maxMachineId || machineId < 0) {
            throw new IllegalArgumentException("Machine ID must be between 0 and " + maxMachineId);
        }
        this.dataCenterId = dataCenterId;
        this.machineId = machineId;
    }

    public synchronized long nextId() {
        long currentTimestamp = System.currentTimeMillis();

        // 处理时钟回拨
        if (currentTimestamp < lastTimestamp) {
            if (retryCount.incrementAndGet() < 10) {
                // 轻微回拨：等待时钟恢复
                currentTimestamp = waitNextMillis(lastTimestamp);
            } else {
                // 严重回拨：生成随机ID（牺牲有序性保证唯一性）
                return generateRandomId();
            }
        }

        if (currentTimestamp == lastTimestamp) {
            sequence = (sequence + 1) & maxSequence;
            if (sequence == 0) {
                // 序列号用尽，等待下一毫秒
                currentTimestamp = waitNextMillis(lastTimestamp);
                sequence = 0L;
            }
        } else {
            // 时间戳改变，重置序列号
            sequence = 0L;
        }

        lastTimestamp = currentTimestamp;
        retryCount.set(0);

        // 生成64位ID
        return ((currentTimestamp - startTimeStamp) << timestampShift) |
                (dataCenterId << dataCenterIdShift) |
                (machineId << machineIdShift) |
                sequence;
    }

    private long waitNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    private long generateRandomId() {
        SecureRandom random = new SecureRandom();
        return (System.currentTimeMillis() - startTimeStamp) << timestampShift |
                random.nextLong() & ((1L << timestampShift) - 1);
    }

    // 从ID提取时间戳
    public long extractTimestamp(long id) {
        return (id >>> timestampShift) + startTimeStamp;
    }
}